/*================================================================
 *   Copyright (C) 2021 All rights reserved.
 *   
 *   文件名称：iomanager.h
 *   创 建 者：汉森伯逸
 *   创建日期：2021/4/2
 *   描    述：
 *
 *================================================================*/
#pragma once

#include "scheduler.h"
#include <atomic>
#include <functional>
#include <sys/epoll.h>

#include "timer.h"

namespace hsby {

/**
 * @brief 将事件类型转换成std::string
 */
static std::string EventFlagsToString(uint32_t et) {
	std::string res;
	if (et == 0x0) return "kEtNone";
    if (et & EPOLLIN) res += "EPOLLIN";
#define TMP(EV) \
    if (et & EV) res += "|" #EV;

    TMP(EPOLLPRI)
    TMP(EPOLLOUT)
    TMP(EPOLLRDNORM)
    TMP(EPOLLRDBAND)
    TMP(EPOLLWRNORM)
    TMP(EPOLLWRBAND)
    TMP(EPOLLMSG)
    TMP(EPOLLERR)
    TMP(EPOLLHUP)
    TMP(EPOLLRDHUP)
    TMP(EPOLLWAKEUP)
    TMP(EPOLLONESHOT)
    TMP(EPOLLET)
#undef TMP
    return res;
}

class IoManager;
class IoWorker : public TimerManager {
public:
    typedef std::shared_ptr<IoWorker> Ptr;

    /**
     * @brief 描述符上下文
     */
    struct FdContext {
        typedef std::shared_ptr<FdContext> Ptr;

        template<typename FiberOrCb>
        int SetEvent(uint32_t ev, FiberOrCb deal) {
            AssertEventFlag(ev);
            if (ev & EPOLLIN) {
                read_task.reset(new Task(deal));
            }else if (ev & EPOLLOUT) {
                write_task.reset(new Task(deal));
            }
            event_flags |= ev;
            return 1;
        }

        int DelEvent(uint32_t ev);

        /**
         * @brief 主动触发事件
         */
        int TriggerEvent(uint32_t evs);

        static void AssertEventFlag(uint32_t ev);

        int fd = -1;
	    Task::Ptr read_task = nullptr;
	    Task::Ptr write_task = nullptr;
        uint32_t event_flags = 0;
    };

public:
    IoWorker(IoManager* iom);

    ~IoWorker();

public:
    /**
     * @brief 工作流程
     */
    void OnWorking();

    /**
     * @brief 唤醒
     */
    void Tickle();

    /**
     * @brief 添加事件
     * @return 修改事件个数
     */
    template<typename FiberOrCb>
    int SetEvent(size_t fd, uint32_t ev, FiberOrCb deal) {
        auto fd_ctx = GetFdContext(fd, true);
        HSBY_ASSERT(fd_ctx);

        // 操作epoll
        int op = fd_ctx->event_flags & ev ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
        epoll_event epevent;
        epevent.events = fd_ctx->event_flags | ev | EPOLLET;
        epevent.data.ptr = fd_ctx.get();


        if (epoll_ctl(epoll_fd_, op, fd, &epevent)) {
            return 0;
        }

        // 设置套接字事件
        return fd_ctx->SetEvent(ev, deal);
    }

    /**
     * @brief 删除事件
     * @return 修改事件个数
     */
    int DelEvent(size_t fd, uint32_t evs);

    /**
     * @brief 触发事件
     * @details 将主动触发事件
     * @return 修改事件个数
     */
    int TriggerEvent(size_t fd, uint32_t evs);

    /**
     * @brief 取消所有事件
     * @details 将主动触发所有事件
     * @return 修改事件个数
     */
    int CancelAll(size_t fd);


protected:
    void OnTimerInsertedAtFront() override;

private:
    FdContext::Ptr GetFdContext(int fd, bool auto_create = false);

private:
    IoManager* iom_;
    std::atomic<bool> on_epoll_wait = {false};
    int epoll_fd_ = 0;
    int tickle_pipe_[2];
    std::unordered_map<int, FdContext::Ptr> fd_contexts_;

public:
    FUNCTION_BUILDER_VAR_GETTER(IoManager, iom_);
};

class IoManager : public Scheduler{
public:
    typedef std::shared_ptr<IoManager> Ptr;

public:
    /**
     * @brief IO管理器构造函数
     */
    IoManager(size_t threads = 1, const std::string& name = "");
    
    /**
     * @brief IO管理器析构函数
     */
    ~IoManager();

public:
    void Dump(std::ostream &os) const override;

protected:
    void Tickle(int thread_id = -1) override;

    void OnIdle() override;

    bool IsStopped() override;

public:
    /**
     * @brief 添加事件
     * @return 修改事件个数
     */
    template<typename FiberOrCb>
    int SetEvent(size_t fd, uint32_t ev, FiberOrCb deal) {
        return GetIoWorkerByDispatchId(fd)->SetEvent(fd, ev, deal);
    }

    /**
     * @brief 删除事件
     * @return 修改事件个数
     */
    int DelEvent(size_t fd, uint32_t evs);

    /**
     * @brief 触发事件
     * @details 将主动触发事件
     * @return 修改事件个数
     */
    int TriggerEvent(size_t fd, uint32_t evs);

    /**
     * @brief 取消所有事件
     * @details 将主动触发所有事件
     * @return 修改事件个数
     */
    int CancelAll(size_t fd);

    /**
     * @brief 添加计时器事件
     */
    Timer::Ptr AddTimer(uint64_t ms, std::function<void()> cb,
                        bool recurring = false);

    /**
     * @brief 添加条件计时器事件
     */
    Timer::Ptr AddConditionTimer(uint64_t ms, std::function<void()> cb,
                                 std::weak_ptr<void> cond_weak,
                                 bool recurring = false);
public:
    /**
     * @brief 获取当前线程的IO管理器
     */
    static IoManager* GetCurrentIoManager();

    static IoWorker::Ptr GetCurrentIoWorker();

private:
    /**
     * @brief 获取分配工作器
     * @param[in] id
     */
    IoWorker::Ptr GetIoWorkerByDispatchId(int id);

    /**
     * @brief 获取线程工作器
     * @param[in] 线程id
     */
    IoWorker::Ptr GetIoWokerByThreadId(int thread_id);

private:
    std::unordered_map<int, IoWorker::Ptr> io_workers_;
};

} // namespace hsby
